Symbol概念及其作用
chenpeng 2020-11-30 ES6基础
# 1.概念
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值,给对象添加属性或方法。它是 JavaScript 的第七种数据类型,是一种类似于字符串的数据类型
Symbol 值通过 Symbol 函数生成,注意 Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
1
2
3
4
5
6
7
2
3
4
5
6
7
Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Symbol 值可以转为字符串和布尔值,但是不能转为数值
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
1
2
3
4
2
3
4
let sym = Symbol();
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 2.作用
# 2.1 使用 Symbol 值作为对象属性名(key)
使用 Symbol 值作为对象的属性名,可以保证不会出现同名的属性。Symbol 值必须放在方括号之中,取值时也必须通过方括号来取值(因为点运算符后面是字符串,不会读取 Symbol 值作为标识名所指代的值)
const name = Symbol();
let obj = {
[name]: '张三',
age: 20
};
console.log(obj); // {age: 20, Symbol(): "张三"}
1
2
3
4
5
6
2
3
4
5
6
Symbol 类型的 key 不能通过 Object.keys() 或 for...in 来枚举,可以使用 Object.getOwnPropertySymbols() 来获取 Symbol 类型的属性名,也可以使用 Reflect.ownKeys() 来获取对象的所有属性名
Object.getOwnPropertySymbols(obj);
Reflect.ownKeys(obj).forEach(item => {
console.log(obj[item]);
})
// 20
// 张三
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2.2 使用 Symbol 代替常量,保证常量的值是唯一的
const log = {};
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2.3 使用 Symbol 定义类的非私有属性或方法
由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
const _name = Symbol();
class Person{
constructor(name) {
this[_name] = name;
}
getName(){
console.log(this[_name]);
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9